(function ($) {
  function getPluginName(target) {
    if ($(target).data('treegrid')) {
      return 'treegrid';
    } else {
      return 'datagrid';
    }
  }

  var autoSizeColumn1 = $.fn.datagrid.methods.autoSizeColumn;
  var loadDataMethod1 = $.fn.datagrid.methods.loadData;
  var appendMethod1 = $.fn.datagrid.methods.appendRow;
  var deleteMethod1 = $.fn.datagrid.methods.deleteRow;
  $.extend($.fn.datagrid.methods, {
    autoSizeColumn: function (jq, field) {
      return jq.each(function () {
        var fc = $(this).datagrid('getPanel').find('.datagrid-header .datagrid-filter-c');
        // fc.hide();
        fc.css({
          width: '1px',
          height: 0
        });
        autoSizeColumn1.call($.fn.datagrid.methods, $(this), field);
        // fc.show();
        fc.css({
          width: '',
          height: ''
        });
        resizeFilter(this, field);
      });
    },
    loadData: function (jq, data) {
      jq.each(function () {
        $.data(this, 'datagrid').filterSource = null;
      });
      return loadDataMethod1.call($.fn.datagrid.methods, jq, data);
    },
    appendRow: function (jq, row) {
      var result = appendMethod1.call($.fn.datagrid.methods, jq, row);
      jq.each(function () {
        var state = $(this).data('datagrid');
        if (state.filterSource) {
          state.filterSource.total++;
          if (state.filterSource.rows != state.data.rows) {
            state.filterSource.rows.push(row);
          }
        }
      });
      return result;
    },
    deleteRow: function (jq, index) {
      jq.each(function () {
        var state = $(this).data('datagrid');
        var opts = state.options;
        if (state.filterSource && opts.idField) {
          if (state.filterSource.rows == state.data.rows) {
            state.filterSource.total--;
          } else {
            for (var i = 0; i < state.filterSource.rows.length; i++) {
              var row = state.filterSource.rows[i];
              if (row[opts.idField] == state.data.rows[index][opts.idField]) {
                state.filterSource.rows.splice(i, 1);
                state.filterSource.total--;
                break;
              }
            }
          }
        }
      });
      return deleteMethod1.call($.fn.datagrid.methods, jq, index);
    }
  });

  var loadDataMethod2 = $.fn.treegrid.methods.loadData;
  var appendMethod2 = $.fn.treegrid.methods.append;
  var insertMethod2 = $.fn.treegrid.methods.insert;
  var removeMethod2 = $.fn.treegrid.methods.remove;
  $.extend($.fn.treegrid.methods, {
    loadData: function (jq, data) {
      jq.each(function () {
        $.data(this, 'treegrid').filterSource = null;
      });
      return loadDataMethod2.call($.fn.treegrid.methods, jq, data);
    },
    append: function (jq, param) {
      return jq.each(function () {
        var state = $(this).data('treegrid');
        var opts = state.options;
        if (opts.oldLoadFilter) {
          var rows = translateTreeData(this, param.data, param.parent);
          state.filterSource.total += rows.length;
          state.filterSource.rows = state.filterSource.rows.concat(rows);
          $(this).treegrid('loadData', state.filterSource)
        } else {
          appendMethod2($(this), param);
        }
      });
    },
    insert: function (jq, param) {
      return jq.each(function () {
        var state = $(this).data('treegrid');
        var opts = state.options;
        if (opts.oldLoadFilter) {
          var ref = param.before || param.after;
          var index = getNodeIndex(param.before || param.after);
          var pid = index >= 0 ? state.filterSource.rows[index]._parentId : null;
          var rows = translateTreeData(this, [param.data], pid);
          var newRows = state.filterSource.rows.splice(0, index >= 0 ? (param.before ? index : index + 1) : (state.filterSource.rows.length));
          newRows = newRows.concat(rows);
          newRows = newRows.concat(state.filterSource.rows);
          state.filterSource.total += rows.length;
          state.filterSource.rows = newRows;
          $(this).treegrid('loadData', state.filterSource);

          function getNodeIndex(id) {
            var rows = state.filterSource.rows;
            for (var i = 0; i < rows.length; i++) {
              if (rows[i][opts.idField] == id) {
                return i;
              }
            }
            return -1;
          }
        } else {
          insertMethod2($(this), param);
        }
      });
    },
    remove: function (jq, id) {
      jq.each(function () {
        var state = $(this).data('treegrid');
        if (state.filterSource) {
          var opts = state.options;
          var rows = state.filterSource.rows;
          for (var i = 0; i < rows.length; i++) {
            if (rows[i][opts.idField] == id) {
              rows.splice(i, 1);
              state.filterSource.total--;
              break;
            }
          }
        }
      });
      return removeMethod2(jq, id);
    }
  });

  var extendedOptions = {
    filterMenuIconCls: 'fal fa-check fa-lg',
    filterBtnIconCls: 'fal fa-filter fa-lg',
    filterBtnPosition: 'right',
    filterPosition: 'bottom',
    remoteFilter: false,
    clientPaging: true,
    showFilterBar: true,
    filterDelay: 400,
    filterRules: [],
    // specify whether the filtered records need to match ALL or ANY of the applied filters
    filterMatchingType: 'all',	// possible values: 'all','any'
    filterIncludingChild: false,
    // filterCache: {},
    filterMatcher: function (data) {
      //console.log('filterMatcher',data)
      var name = getPluginName(this);
      var dg = $(this);
      var state = $.data(this, name);
      var opts = state.options;
      if (opts.filterRules.length) {
        var rows = [];
        if (name == 'treegrid') {
          var rr = {};
          $.map(data.rows, function (row) {
            if (isMatch(row, row[opts.idField])) {
              rr[row[opts.idField]] = row;
              var prow = getRow(data.rows, row._parentId);
              while (prow) {
                rr[prow[opts.idField]] = prow;
                prow = getRow(data.rows, prow._parentId);
              }
              if (opts.filterIncludingChild) {
                var cc = getAllChildRows(data.rows, row[opts.idField]);
                $.map(cc, function (row) {
                  rr[row[opts.idField]] = row;
                });
              }
            }
          });
          for (var id in rr) {
            rows.push(rr[id]);
          }
        } else {
          for (var i = 0; i < data.rows.length; i++) {
            var row = data.rows[i];
            if (isMatch(row, i)) {
              rows.push(row);
            }
          }
        }
        data = {
          total: data.total - (data.rows.length - rows.length),
          rows: rows
        };
      }
      return data;

      function isMatch(row, index) {
    
        if (opts.val == $.fn.combogrid.defaults.val) {
          opts.val = extendedOptions.val;
        }
        var rules = opts.filterRules;
        if (!rules.length) { return true; }
        for (var i = 0; i < rules.length; i++) {
          var rule = rules[i];

          // var source = row[rule.field];
          // var col = dg.datagrid('getColumnOption', rule.field);
          // if (col && col.formatter){
          // 	source = col.formatter(row[rule.field], row, index);
          // }

          var col = dg.datagrid('getColumnOption', rule.field);
          var formattedValue = (col && col.formatter) ? col.formatter(row[rule.field], row, index) : undefined;
          var source = opts.val.call(dg[0], row, rule.field, formattedValue);

          if (source == undefined) {
            source = '';
          }
          var op = opts.operators[rule.op];
          var matched = op.isMatch(source, rule.value);
          if (opts.filterMatchingType == 'any') {
            if (matched) { return true; }
          } else {
            if (!matched) { return false; }
          }
        }
        return opts.filterMatchingType == 'all';
      }
      function getRow(rows, id) {
        for (var i = 0; i < rows.length; i++) {
          var row = rows[i];
          if (row[opts.idField] == id) {
            return row;
          }
        }
        return null;
      }
      function getAllChildRows(rows, id) {
        var cc = getChildRows(rows, id);
        var stack = $.extend(true, [], cc);
        while (stack.length) {
          var row = stack.shift();
          var c2 = getChildRows(rows, row[opts.idField]);
          cc = cc.concat(c2);
          stack = stack.concat(c2);
        }
        return cc;
      }
      function getChildRows(rows, id) {
        var cc = [];
        for (var i = 0; i < rows.length; i++) {
          var row = rows[i];
          if (row._parentId == id) {
            cc.push(row);
          }
        }
        return cc;
      }
    },
    defaultFilterType: 'text',
    defaultFilterOperator: 'contains',
    defaultFilterOptions: {
      onInit: function (target) {
        var name = getPluginName(target);
        var opts = $(target)[name]('options');
        var filterOpts = this.filterOptions;
        var field = $(this).attr('name');
        var input = $(this);
 
        if (input.data('textbox') && !$(this).is('select') && !$(this).is('combobox') && $(this).hasClass('combobox-f') && !$(this).hasClass('combogrid-f')) {
          input = input.textbox('textbox');
        }
            input.unbind('.filter').bind('keydown.filter blur.filter', function (e) {
 
          var t = $(this);
          if (this.timer) {
            clearTimeout(this.timer);
          }
          if (e.keyCode == 13) {
            _doFilter();
          } else if (e.type == 'blur') {
            _doFilter();
          }
        });
        if ($(this).hasClass('daterange')) {
          input.unbind('.filter')
            .unbind('apply.daterangepicker')
            .bind('apply.daterangepicker', function (e,picker) {
                $(this).val(picker.startDate.format('YYYY/MM/DD') + '-' + picker.endDate.format('YYYY/MM/DD'));
                var t = $(this);
                if (this.timer) {
                    clearTimeout(this.timer);
                }
                if (e.keyCode == 13) {
                  _doFilterForDateRange(picker);
                } else {
                    this.timer = setTimeout(function () {
                      _doFilterForDateRange(picker);
                    }, opts.filterDelay);
                }
            });
          input.unbind('.filter')
            .unbind('cancel.daterangepicker')
            .bind('cancel.daterangepicker', function (e, picker) {
                $(this).val('');
                var t = $(this);
                if (this.timer) {
                    clearTimeout(this.timer);
                }
                if (e.keyCode == 13) {
                    _doFilterForDateRange();
                } else {
                    this.timer = setTimeout(function () {
                        _doFilterForDateRange();
                    }, opts.filterDelay);
                }
            });
        }
        //combobox filter
        if ($(this).is('select') || $(this).hasClass('combobox-f')) {
          input.off('.filter').on('combobox.filter', function (e) {
            var t = $(this);
            if (this.timer) {
              clearTimeout(this.timer);
            }
            if (e.keyCode == 13) {
              _doFilterWithCombobox();
            } else {
              this.timer = setTimeout(function () {
                _doFilterWithCombobox();
              }, opts.filterDelay);
            }
          });


        }
        //combogrid filter
        if ($(this).hasClass('combogrid-f')) {
          input.off('.filter').on('combobox.filter', function (e) {
            var t = $(this);
            if (this.timer) {
              clearTimeout(this.timer);
            }
            if (e.keyCode == 13) {
              _doFilterWithCombobox();
            } else {
              this.timer = setTimeout(function () {
                _doFilterWithCombobox();
              }, opts.filterDelay);
            }
          });
        }

        function _doFilter() {
          var rule = $(target)[name]('getFilterRule', field);
          var value = input.val();
     
          if (value != '') {
            if ((rule && rule.value != value) || !rule) {
              var op = rule ? rule.op : (filterOpts ? filterOpts.defaultFilterOperator || opts.defaultFilterOperator : opts.defaultFilterOperator);
              if (value.endsWith('%') || value.endsWith('*')) {
                op = 'beginwith';
              } else if (value.startsWith('%') || value.startsWith('*')) {
                op = 'endwith';
              } else if (value.indexOf('-') > 2 && value.indexOf('-') != (value.length - 1)) {
                op = 'between';
              }
             
              $(target)[name]('addFilterRule', {
                field: field,
                op: op,
                value: value
              });
              $(target)[name]('doFilter');
            }
          } else {
            if (rule) {
              $(target)[name]('removeFilterRule', field);
              $(target)[name]('doFilter');
            }
          }
        }

        function _doFilterWithCombobox() {
          var rule = $(target)[name]('getFilterRule', field);
          var value = input.combobox('getValue');
          var defaultFilterOperator = 'equal';
         
          if (value != '') {
            if ((rule && rule.value != value) || !rule) {
              var op = rule ? rule.op : defaultFilterOperator;
              $(target)[name]('addFilterRule', {
                field: field,
                op: op,
                value: value
              });
              $(target)[name]('doFilter');
            }
          } else {
            if (rule) {
              $(target)[name]('removeFilterRule', field);
              $(target)[name]('doFilter');
            }
          }
        }

        function _doFilterForDateRange() {
            var rule = $(target)[name]('getFilterRule', field);
          var value = input.val();
          var defaultFilterOperator = 'between';
            if (value != '') {
                if ((rule && rule.value != value) || !rule) {
                  var op = rule ? rule.op : defaultFilterOperator;
                    $(target)[name]('addFilterRule', {
                        field: field,
                      op: op,
                        value: value
                    });
                    $(target)[name]('doFilter');
                }
            } else {
              if (rule) {
                $(target)[name]('removeFilterRule', field);
                $(target)[name]('doFilter');
              }
            }
        }
      }
    },
    filterStringify: function (data) {
      return JSON.stringify(data);
    },
    // the function to retrieve the field value of a row to match the filter rule
    val: function (row, field, formattedValue) {
      return formattedValue || row[field];
    },
    onClickMenu: function (item, button) { }
  };
  $.extend($.fn.datagrid.defaults, extendedOptions);
  $.extend($.fn.treegrid.defaults, extendedOptions);
  // filter types
  $.fn.datagrid.defaults.filters = $.extend({}, $.fn.datagrid.defaults.editors, {
    label: {
      init: function (container, options) {
        return $('<span></span>').appendTo(container);
      },
      getValue: function (target) {
        return $(target).html();
      },
      setValue: function (target, value) {
        $(target).html(value);
      },
      resize: function (target, width) {
        $(target)._outerWidth(width)._outerHeight(22);
      }
    }
  });
  $.fn.treegrid.defaults.filters = $.fn.datagrid.defaults.filters;
  // filter operators
  $.fn.datagrid.defaults.operators = {
    nofilter: {
      text: '取消'
    },
    between: {
      text: '之间',
      isMatch: function (source, value) {
        return true;
      }
    },
    contains: {
      text: '包含',
      isMatch: function (source, value) {
        source = String(source);
        value = String(value);
        return source.toLowerCase().indexOf(value.toLowerCase()) >= 0;
      }
    },
    equal: {
      text: '等于',
      isMatch: function (source, value) {
        return source == value;
      }
    },
    notequal: {
      text: '不等于',
      isMatch: function (source, value) {
        return source != value;
      }
    },
    beginwith: {
      text: '以开始',
      isMatch: function (source, value) {
        source = String(source);
        value = String(value);
        return source.toLowerCase().indexOf(value.toLowerCase()) == 0;
      }
    },
    endwith: {
      text: '以结束',
      isMatch: function (source, value) {
        source = String(source);
        value = String(value);
        return source.toLowerCase().indexOf(value.toLowerCase(), source.length - value.length) !== -1;
      }
    },
    less: {
      text: '小于',
      isMatch: function (source, value) {
        return source < value;
      }
    },
    lessorequal: {
      text: '小于等于',
      isMatch: function (source, value) {
        return source <= value;
      }
    },
    greater: {
      text: '大于',
      isMatch: function (source, value) {
        return source > value;
      }
    },
    greaterorequal: {
      text: '大于等于',
      isMatch: function (source, value) {
        return source >= value;
      }
    }
  };
  $.fn.treegrid.defaults.operators = $.fn.datagrid.defaults.operators;
  function resizeFilter(target, field) {
    var toFixColumnSize = false;
    var dg = $(target);
    var header = dg.datagrid('getPanel').find('div.datagrid-header');
    var tr = header.find('.datagrid-header-row:not(.datagrid-filter-row)');
    var ff = field ? header.find('.datagrid-filter[name="' + field + '"]') : header.find('.datagrid-filter');
    ff.each(function () {
      var name = $(this).attr('name');
      var col = dg.datagrid('getColumnOption', name);
      var cc = $(this).closest('div.datagrid-filter-c');
      var btn = cc.find('a.datagrid-filter-btn');
      var cell = tr.find('td[field="' + name + '"] .datagrid-cell');
      var cellWidth = cell._outerWidth();
      if (cellWidth != _getContentWidth(cc)) {
        this.filter.resize(this, cellWidth - btn._outerWidth()-2);
      }
      if (cc.width() > col.boxWidth + col.deltaWidth - 1) {
        col.boxWidth = cc.width() - col.deltaWidth + 1;
        col.width = col.boxWidth + col.deltaWidth;
        toFixColumnSize = true;
      }
    });
    if (toFixColumnSize) {
      $(target).datagrid('fixColumnSize');
    }
    function _getContentWidth(cc) {
      var w = 0;
      $(cc).children(':visible').each(function () {
        w += $(this)._outerWidth();
      });
      return w;
    }
  }
  function getFilterComponent(target, field) {
    var header = $(target).datagrid('getPanel').find('div.datagrid-header');
    return header.find('tr.datagrid-filter-row td[field="' + field + '"] .datagrid-filter');
  }
  /**
  * get filter rule index, return -1 if not found.
  */
  function getRuleIndex(target, field) {
    var name = getPluginName(target);
    var rules = $(target)[name]('options').filterRules;
    for (var i = 0; i < rules.length; i++) {
      if (rules[i].field == field) {
        return i;
      }
    }
    return -1;
  }
  function getFilterRule(target, field) {
    var name = getPluginName(target);
    var rules = $(target)[name]('options').filterRules;
    var index = getRuleIndex(target, field);
    if (index >= 0) {
      return rules[index];
    } else {
      return null;
    }
  }
  function addFilterRule(target, param) {
    var name = getPluginName(target);
    var opts = $(target)[name]('options');
    var rules = opts.filterRules;
    if (param.op == 'nofilter') {
      removeFilterRule(target, param.field);
    } else {
      var index = getRuleIndex(target, param.field);
      if (index >= 0) {
        $.extend(rules[index], param);
      } else {
        rules.push(param);
      }
    }
    var input = getFilterComponent(target, param.field);
    if (input.length) {
      if (param.op != 'nofilter') {
        var value = input.val();
        if (input.data('textbox')) {
          value = input.textbox('getText');
        }
        if (value != param.value) {
          input[0].filter.setValue(input, param.value);
        }
      }
      var menu = input[0].menu;
      if (menu) {
        menu.find('.menu-icon').removeClass(opts.filterMenuIconCls);
        var item = menu.menu('findItem', opts.operators[param.op]['text']);
        menu.menu('setIcon', {
          target: item.target,
          iconCls: opts.filterMenuIconCls
        });
      }
    }
  }
  function removeFilterRule(target, field) {
    var name = getPluginName(target);
    var dg = $(target);
    var opts = dg[name]('options');
    if (field) {
      var index = getRuleIndex(target, field);
      if (index >= 0) {
        opts.filterRules.splice(index, 1);
      }
      _clear([field]);
    } else {
      opts.filterRules = [];
      var fields = dg.datagrid('getColumnFields', true).concat(dg.datagrid('getColumnFields'));
      _clear(fields);
    }
    function _clear(fields) {
      for (var i = 0; i < fields.length; i++) {
        var input = getFilterComponent(target, fields[i]);
        if (input.length) {
          input[0].filter.setValue(input, '');
          var menu = input[0].menu;
          if (menu) {
            menu.find('.' + opts.filterMenuIconCls).removeClass(opts.filterMenuIconCls);
          }
        }
      }
    }
  }
  function doFilter(target) {
    var name = getPluginName(target);
    var state = $.data(target, name);
    var opts = state.options;
    if (opts.remoteFilter) {
      $(target)[name]('load');
    } else {
      if (opts.view.type == 'scrollview' && state.data.firstRows && state.data.firstRows.length) {
        state.data.rows = state.data.firstRows;
      }
      $(target)[name]('getPager').pagination('refresh', { pageNumber: 1 });
      $(target)[name]('options').pageNumber = 1;
      $(target)[name]('loadData', state.filterSource || state.data);
    }
  }
  function translateTreeData(target, children, pid) {
    var opts = $(target).treegrid('options');
    if (!children || !children.length) { return [] }
    var rows = [];
    $.map(children, function (item) {
      item._parentId = pid;
      rows.push(item);
      rows = rows.concat(translateTreeData(target, item.children, item[opts.idField]));
    });
    $.map(rows, function (row) {
      row.children = undefined;
    });
    return rows;
  }
  function myLoadFilter(data, parentId) {
    var target = this;
    var name = getPluginName(target);
    var state = $.data(target, name);
    var opts = state.options;

    if (name == 'datagrid' && $.isArray(data)) {
      data = {
        total: data.length,
        rows: data
      };
    } else if (name == 'treegrid' && $.isArray(data)) {
      var rows = translateTreeData(target, data, parentId);
      data = {
        total: rows.length,
        rows: rows
      }
    }
    if (!opts.remoteFilter || opts.clientPaging) {
      if (!state.filterSource) {
        state.filterSource = data;
      } else {
        if (!opts.isSorting) {
          if (name == 'datagrid') {
            state.filterSource = data;
          } else {
            state.filterSource.total += data.length;
            state.filterSource.rows = state.filterSource.rows.concat(data.rows);
            if (parentId) {
              return opts.filterMatcher.call(target, data);
            }
          }
        } else {
          opts.isSorting = undefined;
        }
      }
      if (!opts.remoteSort && opts.sortName) {
        var names = opts.sortName.split(',');
        var orders = opts.sortOrder.split(',');
        var dg = $(target);
        state.filterSource.rows.sort(function (r1, r2) {
          var r = 0;
          for (var i = 0; i < names.length; i++) {
            var sn = names[i];
            var so = orders[i];
            var col = dg.datagrid('getColumnOption', sn);
            var sortFunc = col.sorter || function (a, b) {
              return a == b ? 0 : (a > b ? 1 : -1);
            };
            r = sortFunc(r1[sn], r2[sn]) * (so == 'asc' ? 1 : -1);
            if (r != 0) {
              return r;
            }
          }
          return r;
        });
      }
      //注解当remotefilter=true时多余
      if (opts.clientPaging === true) {
        data = opts.filterMatcher.call(target, {
          total: state.filterSource.total,
          rows: state.filterSource.rows,
          footer: state.filterSource.footer || []
        });
      }
    }
    if (opts.pagination && opts.clientPaging) {
      var dg = $(target);
      var pager = dg[name]('getPager');
      pager.pagination({
        onSelectPage: function (pageNum, pageSize) {
          opts.pageNumber = pageNum;
          opts.pageSize = pageSize;
          pager.pagination('refresh', {
            pageNumber: pageNum,
            pageSize: pageSize
          });
          // dg[name]('loadData', state.filterSource);
          if (opts.clientPaging) {
            dg[name]('loadData', state.filterSource);
          } else {
            dg[name]('reload');
          }
        },
        onBeforeRefresh: function () {
          dg[name]('reload');
          return false;
        }
      });
      if (name == 'datagrid') {
        var pd = getPageData(data.rows);
        opts.pageNumber = pd.pageNumber;
        data.rows = pd.rows;
      } else {
        var topRows = [];
        var childRows = [];
        $.map(data.rows, function (row) {
          row._parentId ? childRows.push(row) : topRows.push(row);
        });
        data.total = topRows.length;
        var pd = getPageData(topRows);
        opts.pageNumber = pd.pageNumber;
        data.rows = pd.rows.concat(childRows);
      }
    }
    $.map(data.rows, function (row) {
      row.children = undefined;
    });
    return data;

    function getPageData(dataRows) {
      var rows = [];
      var page = opts.pageNumber;
      while (page > 0) {
        var start = (page - 1) * parseInt(opts.pageSize);
        var end = start + parseInt(opts.pageSize);
        rows = dataRows.slice(start, end);
        if (rows.length) {
          break;
        }
        page--;
      }
      return {
        pageNumber: page > 0 ? page : 1,
        rows: rows
      };
    }
  }

  function init(target, filters) {
    filters = filters || [];
    var name = getPluginName(target);
    var state = $.data(target, name);
    var opts = state.options;
    if (!opts.filterRules.length) {
      opts.filterRules = [];
    }
    opts.filterCache = opts.filterCache || {};
    var dgOpts = $.data(target, 'datagrid').options;
    var onResize = dgOpts.onResize;
    dgOpts.onResize = function (width, height) {
      resizeFilter(target);
      onResize.call(this, width, height);
    }
    var onBeforeSortColumn = dgOpts.onBeforeSortColumn;
    dgOpts.onBeforeSortColumn = function (sort, order) {
      var result = onBeforeSortColumn.call(this, sort, order);
      if (result != false) {
        opts.isSorting = true;
      }
      return result;
    };
    var onResizeColumn = opts.onResizeColumn;
    opts.onResizeColumn = function (field, width) {
      var fc = $(this).datagrid('getPanel').find('.datagrid-header .datagrid-filter-c');
      var focusOne = fc.find('.datagrid-filter:focus');
      // fc.hide();
      fc.css({
        width: '1px',
        height: 0
      });
      $(target).datagrid('fitColumns');
      if (opts.fitColumns) {
        resizeFilter(target);
      } else {
        resizeFilter(target, field);
      }
      // fc.show();
      fc.css({
        width: '',
        height: ''
      });
      focusOne.blur().focus();
      onResizeColumn.call(target, field, width);
    };
    var onBeforeLoad = opts.onBeforeLoad;
    opts.onBeforeLoad = function (param1, param2) {
      if (param1) {
        param1.filterRules = opts.filterStringify(opts.filterRules);
      }
      if (param2) {
        param2.filterRules = opts.filterStringify(opts.filterRules);
      }
      var result = onBeforeLoad.call(this, param1, param2);
      if (result != false && opts.url) {
        if (name == 'datagrid') {
          state.filterSource = null;
        } else if (name == 'treegrid' && state.filterSource) {
          if (param1) {
            var id = param1[opts.idField];	// the id of the expanding row
            var rows = state.filterSource.rows || [];
            for (var i = 0; i < rows.length; i++) {
              if (id == rows[i]._parentId) {	// the expanding row has children
                return false;
              }
            }
          } else {
            state.filterSource = null;
          }
        }
      }
      return result;
    };
    if ((opts.view.type == 'detailview' || opts.view.type == 'scrollview') && opts.frozenColumns && opts.frozenColumns.length) {
      var onBeforeRender = opts.view.onBeforeRender;
      opts.view.onBeforeRender = function (target) {
        onBeforeRender.call(opts.view, target)
        if (!opts.detailviewFilterInited) {
          opts.detailviewFilterInited = true;
          var fields = $(target).datagrid('getColumnFields', true);
          if (opts.rownumbers) {
            fields.unshift('_');
          }
          var tr = $(target).data('datagrid').dc.header1.find('.datagrid-filter-row');
          if (tr.length < fields.length) {
            var index = $.inArray('_expander', fields);
            if (index >= 0) {
              var td = tr.children().eq(index);
              if (td.length) {
                $('<td class="_expander"></td>').insertBefore(td);
              } else {
                $('<td class="_expander"></td>').appendTo(tr);
              }
            }
          }
        }
      }
    }
    // opts.loadFilter = myLoadFilter;
    opts.loadFilter = function (data, parentId) {
      var d = opts.oldLoadFilter.call(this, data, parentId);
      return myLoadFilter.call(this, d, parentId);
    };
    state.dc.view2.children('.datagrid-header').unbind('.filter').bind('focusin.filter', function (e) {
      var header = $(this);
      setTimeout(function () {
        state.dc.body2._scrollLeft(header._scrollLeft());
      }, 0);
    });
    initCss();
    createFilter(true);
    createFilter();
    if (opts.fitColumns) {
      setTimeout(function () {
        resizeFilter(target);
      }, 0);
    }
    $.map(opts.filterRules, function (rule) {
      addFilterRule(target, rule);
    });
    function initCss() {
      if (!$('#datagrid-filter-style').length) {
        $('head').append(
          '<style id="datagrid-filter-style">' +
          'a.datagrid-filter-btn{display:inline-block;width:22px;padding-top: 15px;padding-left:3px;;margin:0;vertical-align:middle;cursor:pointer;opacity:0.6;filter:alpha(opacity=60);}' +
          'a:hover.datagrid-filter-btn{opacity:1;filter:alpha(opacity=100);}' +
          '.datagrid-filter-row .textbox,.datagrid-filter-row .textbox .textbox-text{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;}' +
          '.datagrid-filter-row input{margin:0;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;}' +
          '.datagrid-filter-c{overflow:hidden;align-content: center;text-align: center;}' +
          '.datagrid-filter-cache{position:absolute;width:10px;height:10px;left:-99999px;}' +
          '</style>'
        );
      }
    }
    /**
    * create filter component
    */
    function createFilter(frozen) {
      var dc = state.dc;
      var fields = $(target).datagrid('getColumnFields', frozen);
      if (frozen && opts.rownumbers) {
        fields.unshift('_');
      }
      var table = (frozen ? dc.header1 : dc.header2).find('table.datagrid-htable');
      // clear the old filter component
      table.find('.datagrid-filter').each(function () {
        if (this.filter.destroy) {
          this.filter.destroy(this);
        }
        if (this.menu) {
          $(this.menu).menu('destroy');
        }
      });
      table.find('tr.datagrid-filter-row').remove();
      var tr = $('<tr class="datagrid-header-row datagrid-filter-row"></tr>');
      if (opts.filterPosition == 'bottom') {
        tr.appendTo(table.find('tbody'));
      } else {
        tr.prependTo(table.find('tbody'));
      }
      if (!opts.showFilterBar) {
        tr.hide();
      }
      for (var i = 0; i < fields.length; i++) {
        var field = fields[i];
        var col = $(target).datagrid('getColumnOption', field);
        var td = $('<td></td>').attr('field', field).appendTo(tr);
        if (col && col.hidden) {
          td.hide();
        }
        if (field == '_') {
          continue;
        }
        if (col && (col.checkbox || col.expander)) {
          continue;
        }
        var fopts = getFilter(field);
        if (fopts) {
          $(target)[name]('destroyFilter', field);	// destroy the old filter component
        } else {
          fopts = $.extend({}, {
            field: field,
            type: opts.defaultFilterType,
            options: opts.defaultFilterOptions
          });
        }
        var div = opts.filterCache[field];
        if (!div) {
          div = $('<div class="datagrid-filter-c"></div>').appendTo(td);
          var filter = opts.filters[fopts.type];
          var input = filter.init(div, $.extend({ height: opts.editorHeight }, fopts.options || {}));
          input.addClass('datagrid-filter').attr('name', field);
          input[0].filter = filter;
          input[0].filterOptions = fopts;
          input[0].menu = createFilterButton(div, fopts.op);
          if (fopts.op && fopts.op.length) {
            if (fopts.options && fopts.options.onInit) {
              fopts.options.onInit.call(input[0], target);
            } else if (fopts.defaultFilterOperator) {
              opts.defaultFilterOptions.onInit.call(input[0], target);
            }
          } else {
            opts.defaultFilterOptions.onInit.call(input[0], target);
          }
          // if (fopts.options){
          // 	if (fopts.options.onInit){
          // 		fopts.options.onInit.call(input[0], target);
          // 	}
          // } else {
          // 	opts.defaultFilterOptions.onInit.call(input[0], target);
          // }
          opts.filterCache[field] = div;
          resizeFilter(target, field);
        } else {
          div.appendTo(td);
        }
      }
    }
    function createFilterButton(container, operators) {
      if (!operators) { return null; }
      var btn = $('<a class="datagrid-filter-btn">&nbsp;</a>').addClass(opts.filterBtnIconCls);
      btn.css('height', opts.editorHeight);
      if (opts.filterBtnPosition == 'right') {
        btn.appendTo(container);
      } else {
        btn.prependTo(container);
      }
      var menu = $('<div></div>').appendTo('body');
      $.map(['nofilter'].concat(operators), function (item) {
        var op = opts.operators[item];
        if (op) {
          $('<div></div>').attr('name', item).html(op.text).appendTo(menu);
        }
      });
      menu.menu({
        alignTo: btn,
        onClick: function (item) {
          var btn = $(this).menu('options').alignTo;
          var td = btn.closest('td[field]');
          var field = td.attr('field');
          var input = td.find('.datagrid-filter');
          var value = input[0].filter.getValue(input);
          if (opts.onClickMenu.call(target, item, btn, field) == false) {
            return;
          }
          addFilterRule(target, {
            field: field,
            op: item.name,
            value: value
          });
          doFilter(target);
        }
      });
      btn[0].menu = menu;
      btn.bind('click', { menu: menu }, function (e) {
        $(this.menu).menu('show');
        return false;
      });
      return menu;
    }
    function getFilter(field) {
      for (var i = 0; i < filters.length; i++) {
        var filter = filters[i];
        if (filter.field == field) {
          return filter;
        }
      }
      return null;
    }
  }
  $.extend($.fn.datagrid.methods, {
    isFilterEnabled: function (jq) {
      var name = getPluginName(jq[0]);
      var opts = $.data(jq[0], name).options;
      if (opts.oldLoadFilter) {
        return true;
      } else {
        return false;
      }
    },
    enableFilter: function (jq, filters) {
      return jq.each(function () {
        var name = getPluginName(this);
        var opts = $.data(this, name).options;
        if (opts.oldLoadFilter) {
          if (filters) {
            $(this)[name]('disableFilter');
          } else {
            return;
          }
        }
        opts.oldLoadFilter = opts.loadFilter;
        init(this, filters);
        $(this)[name]('resize');
        if (opts.filterRules.length) {
          if (opts.remoteFilter) {
            doFilter(this);
          } else if (opts.data) {
            doFilter(this);
          }
        }
      });
    },
    disableFilter: function (jq) {
      return jq.each(function () {
        var name = getPluginName(this);
        var state = $.data(this, name);
        var opts = state.options;
        if (!opts.oldLoadFilter) {
          return;
        }
        var dc = $(this).data('datagrid').dc;
        var div = dc.view.children('.datagrid-filter-cache');
        if (!div.length) {
          div = $('<div class="datagrid-filter-cache"></div>').appendTo(dc.view);
        }
        for (var field in opts.filterCache) {
          $(opts.filterCache[field]).appendTo(div);
        }
        var data = state.data;
        if (state.filterSource) {
          data = state.filterSource;
          $.map(data.rows, function (row) {
            row.children = undefined;
          });
        }
        dc.header1.add(dc.header2).find('tr.datagrid-filter-row').remove();
        opts.loadFilter = opts.oldLoadFilter || undefined;
        opts.oldLoadFilter = null;
        $(this)[name]('resize');
        $(this)[name]('loadData', data);
        // $(this)[name]({
        // 	data: data,
        // 	loadFilter: (opts.oldLoadFilter||undefined),
        // 	oldLoadFilter: null
        // });
      });
    },
    destroyFilter: function (jq, field) {
      return jq.each(function () {
        var name = getPluginName(this);
        var state = $.data(this, name);
        var opts = state.options;
        if (field) {
          _destroy(field);
        } else {
          for (var f in opts.filterCache) {
            _destroy(f);
          }
          $(this).datagrid('getPanel').find('.datagrid-header .datagrid-filter-row').remove();
          $(this).data('datagrid').dc.view.children('.datagrid-filter-cache').remove();
          opts.filterCache = {};
          $(this)[name]('resize');
          $(this)[name]('disableFilter');
        }
        function _destroy(field) {
          var c = $(opts.filterCache[field]);
          var input = c.find('.datagrid-filter');
          if (input.length) {
            var filter = input[0].filter;
            if (filter.destroy) {
              filter.destroy(input[0]);
            }
          }
          c.find('.datagrid-filter-btn').each(function () {
            $(this.menu).menu('destroy');
          });
          c.remove();
          opts.filterCache[field] = undefined;
        }
      });
    },
    getFilterRule: function (jq, field) {
      return getFilterRule(jq[0], field);
    },
    addFilterRule: function (jq, param) {
      return jq.each(function () {
        addFilterRule(this, param);
      });
    },
    removeFilterRule: function (jq, field) {
      return jq.each(function () {
        removeFilterRule(this, field);
      });
    },
    doFilter: function (jq) {
      return jq.each(function () {
        doFilter(this);
      });
    },
    getFilterComponent: function (jq, field) {
      return getFilterComponent(jq[0], field);
    },
    resizeFilter: function (jq, field) {
      return jq.each(function () {
        resizeFilter(this, field);
      });
    }
  });
})(jQuery);
